package com.winning.util.excelutil.service.impl;

import com.alibaba.excel.ExcelReader;
import com.alibaba.excel.metadata.Sheet;
import com.winning.util.excelutil.common.exception.BaseException;
import com.winning.util.excelutil.excel.ExcelListener;
import com.winning.util.excelutil.excel.ExcelUtil;
import com.winning.util.excelutil.service.ImportService;
import com.winning.util.excelutil.util.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @作者： caopengfei
 * @时间： 2020/2/13
 */
@Service
@Slf4j
public class ImportServiceImpl implements ImportService {

    @Autowired
    NamedParameterJdbcTemplate namedParameterJdbcTemplate;

    @Override
    /*    @Transactional*/
    public void importExcel(MultipartFile file) {
        importExcel2(file);
    }

    /**
     * @vsts_no：
     * @comment： 导入数据
     * @author： caopengfei
     * @time： 2020/2/14 19:58
     */
    private void importExcel2(MultipartFile file) {
        ExcelListener excelListener = new ExcelListener();
        ExcelReader reader = ExcelUtil.getReader(file, excelListener);
        List<Sheet> sheets = reader.getSheets();

        for (int i = 0; i < sheets.size(); i++) {
            Sheet sheet = sheets.get(i);
            String[] sheetNameArr = sheet.getSheetName().split("\\+");
            String tableName = sheetNameArr[0];
            List<Object> datas = ExcelUtil.readExcel(file, i + 1);

            //获取数据库字段
            List<String> columns = (List) datas.get(1);

            checkColumn(columns);
            //获取数据
            Map<String, Object>[] params = getParamMaps(datas, columns);
            //如果表不存在，创建表
            createTable(tableName, columns);
            // 获取指定主键列数
            if (sheetNameArr.length == 2 && Integer.parseInt(sheetNameArr[1]) > 0) {
                insertOrUpdate(tableName, columns.subList(0, Integer.parseInt(sheetNameArr[1])), columns, params);
            } else {
                String sql = createInsertSql(tableName, columns);
                namedParameterJdbcTemplate.batchUpdate(sql, params);
            }

        }
    }

    /**
     * @param updateIndex
     * @return
     */
    private static Integer[] getUpdateIndex(String updateIndex) {
        if (StringUtils.isEmpty(updateIndex)) {
            return new Integer[]{};
        }
        Integer[] updateIndexArr;
        try {
            updateIndexArr = Arrays.asList(updateIndex.split(",")).stream()
                    .map(e -> Integer.parseInt(e)).collect(Collectors.toList())
                    .stream().toArray(Integer[]::new);
        } catch (Exception e) {
            throw new BaseException("主键是excel前N列配置错误，请确认！");
        }
        return updateIndexArr;
    }


    /**
     * 插入更新
     *
     * @param tableName
     * @param indexColumn
     * @param columns
     * @param datas
     */
    private void insertOrUpdate(String tableName, List<String> indexColumn, List<String> columns, Map<String, Object>[] datas) {
        for (Map<String, Object> data : datas) {
            //校验数据是否存在
            boolean isExist = isExists(tableName, indexColumn, data);
            data.put("isExist", isExist);
        }
        //更新
        Map<String, Object>[] updateDatas = Arrays.asList(datas).stream().filter(map -> {
            return (boolean) map.get("isExist");
        }).collect(Collectors.toList())
                .stream().toArray(Map[]::new);
        if (updateDatas.length > 0) {
            String updataSql = createUpdateSql(tableName, columns, indexColumn);
            namedParameterJdbcTemplate.batchUpdate(updataSql, updateDatas);
        }

        //插入
        Map<String, Object>[] insertDatas = Arrays.asList(datas).stream().filter(map -> {
            return !(boolean) map.get("isExist");
        }).collect(Collectors.toList()).stream().toArray(Map[]::new);
        if (insertDatas.length > 0) {
            String insertSql = createInsertSql(tableName, columns);
            namedParameterJdbcTemplate.batchUpdate(insertSql, insertDatas);
        }
    }

    /**
     * 如果表不存在，创建表
     * @param tableName
     * @param columns
     * @return
     */
    private void createTable(String tableName, List<String> columns) {
        String querySql = "select count(1) as count from " +tableName;
        try {
            namedParameterJdbcTemplate.queryForObject(querySql, new HashMap<>(), Integer.class);
        } catch (Exception e) {
            //如果当前表名不存在，查询异常，根据表名、列名创建新表
            StringBuilder createSql =  new StringBuilder();
            createSql.append("CREATE TABLE ").append(tableName).append("(");
            for (int i = 0; i < columns.size(); i++) {
                String colname = columns.get(i);
                if (i == columns.size() - 1) {
                    createSql.append(colname).append(" varchar(500))");
                } else {
                    createSql.append(colname).append(" varchar(500),\n");
                }
            }
            String create = createSql.toString();
            log.info("建表语句：", create);
            namedParameterJdbcTemplate.update(createSql.toString(),new HashMap());
        }
    }


    /**
     * @vsts_no：
     * @comment： 获取参数集合
     * @author： caopengfei
     * @time： 2020/2/13 19:23
     */
    private Map<String, Object>[] getParamMaps(List<Object> datas, List<String> columns) {
        Map<String, Object>[] params = new Map[datas.size() - 2];
        for (int i = 2; i < datas.size(); i++) {
            List<String> row = (List) datas.get(i);
            Map<String, Object> param = new HashMap<String, Object>();
            for (int j = 0; j < columns.size(); j++) {
                //如果字段为空则跳过
                if (StringUtils.isEmpty(columns.get(i))) {
                    continue;
                }
                String value = null;
                if (row.size() >= (j + 1)) {
                    value = row.get(j);
                    if (StringUtils.isEmpty(value)) {
                        value = null;
                    }
                }
                param.put(columns.get(j), value);
            }
            params[i - 2] = param;
        }
        return params;
    }

    /**
     * @vsts_no：
     * @comment： 获取新增的sql
     * @author： caopengfei
     * @time： 2020/2/13 19:23
     */
    private String createInsertSql(String tableName, List<String> columns) {
        StringBuilder insert = new StringBuilder();
        StringBuilder values = new StringBuilder();

        insert.append(" insert into  ").append(tableName).append(" ( ");
        values.append(" values( ");
        //2.遍历所有的字段
        for (String field : columns) {
            //如果字段则拼接
            if (StringUtils.isNotEmpty(field)) {
                insert.append(field).append(",");
                values.append(":").append(field).append(",");
            }
        }
        insert.deleteCharAt(insert.length() - 1);
        insert.append(") ");
        values.deleteCharAt(values.length() - 1);
        values.append(") ");
        insert.append(values);
        return insert.toString();
    }

    /**
     * @vsts_no：
     * @comment： 拼接更新SQL
     * @author： caopengfei
     * @time： 2020/2/15 16:26
     */
    private String createUpdateSql(String tableName, List<String> columns, List<String> indexColumns) {
        StringBuilder update = new StringBuilder();
        update.append(" update ").append(tableName).append(" set ");
        //2.遍历所有的字段
        for (int i = 0; i < columns.size(); i++) {
            String field = columns.get(i);
            update.append(" ").append(field).append("=:").append(field).append(",");
        }
        update.deleteCharAt(update.length() - 1);
        update.append(createWhere(indexColumns));
        return update.toString();
    }

    /**
     * @vsts_no：
     * @comment： 拼接查询sql
     * @author： caopengfei
     * @time： 2020/2/15 16:26
     */
    private String createSelect(String tableName, List<String> indexColumns) {
        return " select count(1) as count from " + tableName + createWhere(indexColumns);
    }

    /**
     * @vsts_no：
     * @comment： 判断记录是否存在
     * @author： caopengfei
     * @time： 2020/2/16 9:32
     */
    private boolean isExists(String tableName, List<String> indexColumns, Map<String, Object> params) {
        String querySql = createSelect(tableName, indexColumns);
        int result = 0;
        try {
            result = namedParameterJdbcTemplate.queryForObject(querySql, params, Integer.class);
        } catch (Exception e) {
            //如果当前表名不存在，查询异常，根据表名、列名创建新表
            int a = 1;
            namedParameterJdbcTemplate.execute("CREATE TABLE test (YLJGLX varchar(20))",ps -> null);
        }
        return result > 0;
    }

    /**
     * @vsts_no：
     * @comment： 拼接where 条件
     * @author： caopengfei
     * @time： 2020/2/15 16:36
     */
    private String createWhere(List<String> indexColumns) {
        StringBuilder where = new StringBuilder();
        where.append(" where 1 = 1 ");
        for (int i = 0; i < indexColumns.size(); i++) {
            String field = indexColumns.get(i);
            where.append(" and ").append(field).append("=:").append(field);
        }
        return where.toString();
    }

    /**
     * @vsts_no：
     * @comment： 校验字段是否有留白
     * @author： caopengfei
     * @time： 2020/2/14 19:55
     */
    private void checkColumn(List<String> columns) {
        boolean lastColumnIsNull = StringUtils.isEmpty(columns.get(columns.size() - 1));
        for (int i = (columns.size() - 1); i > 0; i--) {
            String column = columns.get(i);
            //如果第二行的字段列 表格中间空格.
            if ((!lastColumnIsNull) && StringUtils.isEmpty(column) && i < columns.size() - 1) {
                throw new BaseException("excel 第一行，第二行不能有间隔空列，请检查");
            }
        }
    }

}
